package triangle;

import triangle.reader.BackwardsFileReader;

/**
 * This file is part of Rodney Ryan's submission of
 * his solution to the "Triangle Puzzle".
 * <p/>
 * This class reads data for a triangle from a
 * file. Rows are loaded from bottom to top.
 *
 * rodney@rodneyryan.com
 */
public class TriangleFile implements Triangle {

    private BackwardsFileReader backwardsFileReader;

    private String savedLastRow;
    private int numberOfRows;

    public TriangleFile(String fileName, int allAtOnceSizeLimit_MB) {
        super();
        backwardsFileReader = new BackwardsFileReader(fileName, allAtOnceSizeLimit_MB);

        savedLastRow = null;
        numberOfRows = -1;

        calculateNumberOfRows();
    }

    private void calculateNumberOfRows() {
        savedLastRow = backwardsFileReader.readLine();
        if (savedLastRow == null) {
            numberOfRows = 0;

        } else {
            numberOfRows = 1;
            int separatorIndex = savedLastRow.indexOf(' ');
            while (separatorIndex != -1) {
                numberOfRows++;
                separatorIndex = savedLastRow.indexOf(' ', separatorIndex + 1);
            }
        }
    }

    private void handleInvalidRow(String row) {
        System.out.println("\nError - invalid triangle row.");
        System.out.println("Row : \"" + row + "\"");

        dispose();
        System.exit(-1);
    }

    private int fillBuffer(String row, long[] buffer) {
        int count;

        if (row.length() == 0) {
            count = 0;

        } else {
            int beginIndex = 0;
            int endIndex = row.indexOf(' ');

            if (endIndex == -1) {
                buffer[0] = Long.parseLong(row);
                count = 1;

            } else {
                count = 0;
                while (endIndex != -1) {
                    if (count > buffer.length - 1) {
                        handleInvalidRow(row);
                    }
                    buffer[count] = Long.parseLong(row.substring(beginIndex, endIndex));
                    count++;
                    beginIndex = endIndex + 1;
                    endIndex = row.indexOf(' ', beginIndex);
                }
                buffer[count] = Long.parseLong(row.substring(beginIndex, row.length()));
                count++;
            }
        }

        return count;
    }

    @Override
    public int getNumberOfRows() {
        return numberOfRows;
    }

    private int handleBadValue(String row, NumberFormatException e) {
        System.out.println("\nError - could not convert row value to number.");
        System.out.println("Row contents  : \"" + row + "\"");
        System.out.println("Detail message: " + e.getMessage());

        dispose();
        System.exit(-1);
        return 0;
    }

    @Override
    public int loadRow(long[] buffer) {
        String row;
        if (savedLastRow != null) {
            row = savedLastRow;
            savedLastRow = null;
        } else {
            row = backwardsFileReader.readLine();
        }

        if (row != null) {
            try {
                return fillBuffer(row, buffer);
            } catch (NumberFormatException e) {
                return handleBadValue(row, e);
            }

        } else {
            dispose();
            return 0;
        }
    }

    @Override
    public void dispose() {
        backwardsFileReader.close();
    }
}
